package com.zmn.mcc.business.impl.role;

import com.zmn.common.dictionary.GlobalDict;
import com.zmn.common.dto.LoginStaff;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.mcc.business.interfaces.role.RoleStaffBService;
import com.zmn.mcc.business.interfaces.staff.StaffBService;
import com.zmn.mcc.business.interfaces.staff.ip.StaffIpInfoBService;
import com.zmn.mcc.common.constant.StaffChangeLogConsts;
import com.zmn.mcc.model.entity.log.IpInfo;
import com.zmn.mcc.model.entity.role.McRole;
import com.zmn.mcc.model.entity.role.McRoleQuery;
import com.zmn.mcc.model.entity.role.McRoleStaff;
import com.zmn.mcc.model.entity.staff.staffchangelog.StaffChangeLog;
import com.zmn.mcc.services.interfaces.role.RoleService;
import com.zmn.mcc.services.interfaces.role.RoleStaffService;
import com.zmn.mcc.services.interfaces.staff.staffchangelog.StaffChangeLogService;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author heguanghua
 * @since 2020/04/14 23:06
 */
@Service
public class RoleStaffBServiceImpl implements RoleStaffBService {
    protected Logger logger = LoggerFactory.getLogger(RoleStaffBServiceImpl.class);

    @Resource
    private RoleStaffService roleStaffService;
    @Resource
    private RoleService roleService;
    @Resource
    private StaffBService staffBService;
    @Resource
    private StaffChangeLogService staffChangeLogService;
    @Resource
    StaffIpInfoBService staffIpInfoBService;

    private static final Integer ADD_STAFF_ROLE = 1;
    private static final Integer DELETE_STAFF_ROLE = 2;



    // region 为指定员工添加角色

    @Override
    public ResponseDTO addRoleStaff(Integer staffId, List<Integer> roleIds, LoginStaff loginStaff, String ip) {

        try {

            List<McRoleStaff> roleStaffs = new ArrayList<>();
            for (Integer roleId : roleIds) {
                roleStaffs.add(new McRoleStaff(roleId, staffId));
            }

            // 记录员工校色变更日志
            insertStaffRoleChangeLog(staffId, roleIds, loginStaff, ADD_STAFF_ROLE, ip);

            // 分配角色
            roleStaffService.insertByBatch(roleStaffs);

            // 修改员工自定义功能权限标识
            staffBService.setPermitSelf(staffId, GlobalDict.YESNO_YES, loginStaff.getRealName());

            logger.info(String.format("[ZMN]为指定员工添加角色成功,staffId:[%s],roleIds:[%s],operator:[%s]", staffId, StringUtil.convertListToStrs(roleIds), loginStaff.getRealName()));
            return ResponseDTO.success(null, "为指定员工添加角色成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]为指定员工添加角色出错,staffId:[%s],roleIds:[%s],operator:[%s],ex:[%s]", staffId, StringUtil.convertListToStrs(roleIds), loginStaff.getRealName(), ex.getMessage()));
            return ResponseDTO.fail("为指定员工添加角色失败");
        }

    }
    // endregion

    // region 移除指定员工的角色

    @Override
    public ResponseDTO deleteRoleStaff(Integer staffId, List<Integer> roleIds, LoginStaff loginStaff, String ip) {

        try {

            // 记录员工校色变更日志
            insertStaffRoleChangeLog(staffId, roleIds, loginStaff, DELETE_STAFF_ROLE, ip);

            // 移除已分配角色
            for (Integer roleId : roleIds) {
                roleStaffService.deleteByKey(roleId, staffId);
            }

            // 修改员工自定义功能权限标识
            staffBService.setPermitSelf(staffId, loginStaff.getRealName());

            logger.info(String.format("[ZMN]移除指定员工的角色成功,staffId:[%s],roleIds:[%s],operator:[%s]", staffId, StringUtil.convertListToStrs(roleIds), loginStaff.getRealName()));
            return ResponseDTO.success(null, "移除指定员工的角色成功");

        } catch (Exception ex) {
            logger.error(String.format("[ZMN]移除指定员工的角色出错,staffId:[%s],roleIds:[%s],operator:[%s],ex:[%s]", staffId, StringUtil.convertListToStrs(roleIds), loginStaff.getRealName(), ex.getMessage()));
            return ResponseDTO.fail("移除指定员工的角色失败");
        }

    }

    @Override
    public void deleteRoleByStaffId(Integer roleId, Integer staffId, LoginStaff loginStaff, String ip) {

        // 记录员工角色变更日志
        insertStaffRoleChangeLog(staffId, Collections.singletonList(roleId), loginStaff, DELETE_STAFF_ROLE, ip);
        roleStaffService.deleteByKey(roleId, staffId);

    }
    // endregion

    /**
     * 记录员工角色表更日志
     * @param staffId
     * @param roleIds
     * @param loginStaff
     * @param addOrDeleteFlag 1表示新增 2表示删除
     */
    private void insertStaffRoleChangeLog(Integer staffId, List<Integer> roleIds, LoginStaff loginStaff, Integer addOrDeleteFlag, String ip) {
        // 添加员工角色变更日志
        List<Integer> hisRoles = roleStaffService.listRoleIdByStaffId(staffId);
        List<Integer> nowRoles = roleIds;

        if (Objects.equals(ADD_STAFF_ROLE, addOrDeleteFlag)) {
            nowRoles.removeAll(hisRoles);
            nowRoles.addAll(hisRoles);
        } else if (Objects.equals(DELETE_STAFF_ROLE, addOrDeleteFlag)) {
            List<Integer> tempRoles = new ArrayList<>();
            tempRoles.addAll(hisRoles);
            tempRoles.removeAll(nowRoles);
            nowRoles = tempRoles;
        }

        // 如果角色修改，则记录日志
        if (!isListEqual(hisRoles, nowRoles)) {
            McRoleQuery roleQuery;
            List<McRole> hisRoleList = new ArrayList<>(hisRoles.size());
            List<McRole> nowRoleList = new ArrayList<>(nowRoles.size());
            if (CollectionUtils.isNotEmpty(hisRoles)) {
                roleQuery = new McRoleQuery();
                roleQuery.setRoleIds(hisRoles);
                hisRoleList = roleService.listByQuery(roleQuery);
            }
            if (CollectionUtils.isNotEmpty(nowRoles)) {
                roleQuery = new McRoleQuery();
                roleQuery.setRoleIds(nowRoles);
                nowRoleList = roleService.listByQuery(roleQuery);
            }
            // 员工角色变更需要记录日志
            StaffChangeLog staffChangeLog = new StaffChangeLog();
            staffChangeLog.setStaffId(staffId);

            if (CollectionUtils.isNotEmpty(hisRoleList)) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hisRoleList.size(); i++) {
                    sb.append(i == 0 ? hisRoleList.get(i).getRoleName() : "," + hisRoleList.get(i).getRoleName());
                }
                staffChangeLog.setBeforContent(sb.toString());
            } else {
                staffChangeLog.setBeforContent("-");
            }

            if (CollectionUtils.isNotEmpty(nowRoleList)) {
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < nowRoleList.size(); i++) {
                    sb.append(i == 0 ? nowRoleList.get(i).getRoleName() : "," + nowRoleList.get(i).getRoleName());
                }
                staffChangeLog.setAfterContent(sb.toString());
            } else {
                staffChangeLog.setAfterContent("-");
            }

            staffChangeLog.setAbutmenterId(loginStaff.getStaffId());
            staffChangeLog.setAbutmenter(loginStaff.getRealName());
            staffChangeLog.setAbutmenterDeptId(loginStaff.getDeptId() + "");
            staffChangeLog.setAbutmenterDeptName(loginStaff.getDeptName());
            staffChangeLog.setChangeType(StaffChangeLogConsts.CHANGE_TYPE_EDIT_ROLE);
            staffChangeLog.setCreateTime(DateUtil.getNow());
            IpInfo ipInfo = staffIpInfoBService.locationByIP(ip);
            staffChangeLog.setIp(ip);
            if (Objects.nonNull(ipInfo)) {
                staffChangeLog.setAbutmenterCity(ipInfo.getProvince() + "-" + ipInfo.getCity());
            }
            staffChangeLogService.insert(staffChangeLog);
        }
    }

    /**
     * 比较两个List集合是否相等
     * <p>注：1. 如果一个List的引用为<code>null</code>，或者其包含的元素个数为0，那么该List在本逻辑处理中都算作空；
     * <p>2. 泛型参数E涉及到对象，所以需要确保正确实现了对应对象的<code>equal()</code>方法。
     *
     * @param list1
     * @param list2
     * @return
     */
    public static boolean isListEqual(List<Integer> list1, List<Integer> list2) {
        // 两个list引用相同（包括两者都为空指针的情况）
        if (list1 == list2) {
            return true;
        }

        // 两个list都为空（包括空指针、元素个数为0）
        if ((list1 == null && list2 != null && list2.size() == 0)
                || (list2 == null && list1 != null && list1.size() == 0)) {
            return true;
        }

        // 两个list元素个数不相同
        if (list1.size() != list2.size()) {
            return false;
        }

        // 两个list元素个数已经相同，再比较两者内容
        // 采用这种可以忽略list中的元素的顺序
        // 涉及到对象的比较是否相同时，确保实现了equals()方法
        if (!list1.containsAll(list2)) {
            return false;
        }

        return true;
    }
}
